-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.


local c_object = require 'mc.orm.object'
local log = require 'mc.logging'
local c_fan_group_object = require 'fan_group_object'
local power_supplies = require 'power_supplies'
local context = require 'mc.context'
local basic_cooling_config = c_object('BasicCoolingConfig')

local DEFAULT_GROUP_SPEED_THRESHOLD<const> = 32767
local DEFAULT_PSU_FAN_SPEED_CAL<const> = 32767

function basic_cooling_config:ctor()
    self.pre_psu_level = 0 -- 记录上一次下发的psu转速比
    self.max_level = 0 -- 所有风扇组中最大风扇转速
    self.power_supplies_instance = power_supplies.get_instance()
end

function basic_cooling_config:init()
    self:connect_signal(self.on_add_object, function()
    end)
    self:connect_signal(self.on_add_object_complete, function()
        log:notice('on_add_object_complete, FanGroupSpeedDiffThresholdPercent: %s, PsuFanSpeedCalibration: %s',
            self.FanGroupSpeedDiffThresholdPercent, self.PsuFanSpeedCalibration)
    end)
    basic_cooling_config.super.init(self)
end

local function fan_speed_adjust_check(fan_speed, cur_fan_group_obj_id, other_fan_group_obj_id)
    if not fan_speed then
        return false
    end
    if cur_fan_group_obj_id == other_fan_group_obj_id then
        return false
    end
    return true
end

-- 风扇组间转速差计算
function basic_cooling_config:fan_group_speed_adjust(fan_table)
    -- 无风扇组配置对象或者风扇组转速差属性为默认值，则不进行转速差计算
    if not self.FanGroupSpeedDiffThresholdPercent or
        self.FanGroupSpeedDiffThresholdPercent == DEFAULT_GROUP_SPEED_THRESHOLD then
        return fan_table
    end

    self.max_level = 0
    c_fan_group_object.collection:fold(function (_, fan_group_obj)
        fan_group_obj.max_speed_percent = 0 -- 清除上一次的数据，初始化为最小值
        for _, slot in pairs(fan_group_obj.FanSlots) do
            -- 防止风扇对象与风扇组配置不匹配
            if not fan_table[slot] then
                goto continue
            end
            self.max_level = math.max(self.max_level, fan_table[slot])

            ::continue::
        end
    end)

    -- 计算每个风扇组转速调整后的最大转速值
    c_fan_group_object.collection:fold(function (_, fan_group_obj)
        for _, slot in pairs(fan_group_obj.FanSlots) do
            if not fan_table[slot] then
                goto continue
            end
            fan_group_obj.max_speed_percent = math.max(
                fan_table[slot], fan_group_obj.max_speed_percent
            )

            ::continue::
        end
        -- 风扇组最大转速值还需要与所有风扇最大转转速减去阈值取大
        fan_group_obj.max_speed_percent = math.max(
            fan_group_obj.max_speed_percent, self.max_level - self.FanGroupSpeedDiffThresholdPercent
        )
    end)

    -- 计算每个风扇的调整后的转速
    c_fan_group_object.collection:fold(function (_, cur_fan_group_obj)
        -- 当前风扇组的风扇与其他所有组风扇进行对比计算
        for _, slot in pairs(cur_fan_group_obj.FanSlots) do
            c_fan_group_object.collection:fold(function (_, other_fan_group_obj)
                fan_table[slot] = fan_speed_adjust_check(fan_table[slot], cur_fan_group_obj.Id, other_fan_group_obj.Id)
                    and math.max(
                        fan_table[slot], other_fan_group_obj.max_speed_percent - self.FanGroupSpeedDiffThresholdPercent
                    ) or fan_table[slot]
            end)
        end
    end)

    self:set_psu_fan()

    return fan_table
end


function basic_cooling_config:set_psu_fan()
    -- 如果配置了psu风扇转速校准值，且转速相较于上次下发发生了变化则下发转速
    if self.PsuFanSpeedCalibration ~= DEFAULT_PSU_FAN_SPEED_CAL and self.max_level ~= self.pre_psu_level then
        self.pre_psu_level = self.max_level
        self.power_supplies_instance:set_psu_fan_pwm(
            context.get_context_or_default(), self.max_level + self.PsuFanSpeedCalibration
        )
    end
end

return basic_cooling_config